package org.ouwh.fw.db;

import java.sql.Connection;
import java.util.Properties;

import javax.management.Notification;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ouwh.fw.model.data.Struct;
import org.ouwh.fw.model.service.Service;

public class JdbcPoolService extends Service {
	private static final String FREE_SIZE = "free-size";

	private static final String SIZE = "size";

	private static final String TIMEOUT = "timeout";

	private static final String INTERVAL = "interval";

	private static final String MIN_SIZE = "min-size";

	private static final String MAX_SIZE = "max-size";

	private static final String DRIVER = "driver";

	private static final String USER = "user";

	private static final String URL = "url";

	private static final String PASSWORD = "password";

	private static Log log = LogFactory.getLog(JdbcPoolService.class);

	private JdbcPool jdbcPool = null;

	private volatile boolean running = false;

	@Override
	protected void init(Properties props) {
		log.debug("Jdbc Url: " + props.getProperty(URL));
		String pwd = null;
		try {
			pwd = getPassword(props, PASSWORD);
		} catch (Exception e) {
			pwd = props.getProperty(PASSWORD);
		}
		jdbcPool = new JdbcPool(props.getProperty(URL), props.getProperty(USER), pwd, props.getProperty(DRIVER),
				Integer.parseInt(props.getProperty(MAX_SIZE)), Integer.parseInt(props.getProperty(MIN_SIZE)),
				Long.parseLong(props.getProperty(INTERVAL)), Long.parseLong(props.getProperty(TIMEOUT)));
		log.info("JdbcPoolService[" + getId() + "]initialized.");
	}

	@Override
	protected void startup() throws Exception {
		if (running) {
			return;
		}
		jdbcPool.open();
		running = true;
		log.info("JdbcPoolService[" + getId() + "]started.");
	}

	@Override
	protected void reset(Properties props) throws Exception {
		jdbcPool.setJdbcURL(props.getProperty(URL));
		jdbcPool.setJdbcUserName(props.getProperty(USER));
		jdbcPool.setJdbcPassword(getPassword(props, PASSWORD));
		jdbcPool.setJdbcDriver(props.getProperty(DRIVER));
		jdbcPool.setMaxSize(Integer.parseInt(props.getProperty(MAX_SIZE)));
		jdbcPool.setMinSize(Integer.parseInt(props.getProperty(MIN_SIZE)));
		jdbcPool.setInterval(Long.parseLong(props.getProperty(INTERVAL)));
		jdbcPool.setTimeout(Long.parseLong(props.getProperty(TIMEOUT)));
		log.info("JdbcPoolService[" + getId() + "]resetted.");
	}

	@Override
	protected void shutdown() {
		if (!running) {
			return;
		}
		log.info("JdbcPoolService[" + getId() + "]stopping...");
		running = false;
		jdbcPool.close();
		synchronized (this) {
			this.notify();
		}
		log.info("JdbcPoolService[" + getId() + "]stopped.");
	}

	@Override
	protected void dumpToStruct(Struct struct) {
		jdbcPool.dumpBusyThreads();
		struct.addData(URL, jdbcPool.getJdbcURL());
		struct.addData(USER, jdbcPool.getJdbcUserName());
		struct.addData(DRIVER, jdbcPool.getJdbcDriver());
		struct.addData(MAX_SIZE, jdbcPool.getMaxSize());
		struct.addData(MIN_SIZE, jdbcPool.getMinSize());
		struct.addData(INTERVAL, jdbcPool.getInterval());
		struct.addData(TIMEOUT, jdbcPool.getTimeout());
		struct.addData(SIZE, jdbcPool.size());
		struct.addData(FREE_SIZE, jdbcPool.freeSize());
	}

	public Connection getConnection() throws Exception {
		Connection conn = null;
		int count = 0;
		while ((count++ < 3) && running) {
			conn = jdbcPool.getConnection();
			if (conn == null) {
				synchronized (this) {
					try {
						this.wait(3000);
					} catch (InterruptedException e) {
					}
				}
			} else {
				return conn;
			}
		}
		String message = "JdbcPoolService[" + this.getId() + "]has no more free connection";
		Notification n = new Notification("WARN", this.getId(), 0, message);
		sendNotification(n);
		throw new Exception(message);
	}

	public JdbcPool getRawPool() {
		return jdbcPool;
	}

}
